/**
 *  exceljs + handsontable
 */
import Excel from "exceljs";
import React, { useState } from "react";
import { HotTable } from "@handsontable/react";
import { registerAllModules } from "handsontable/registry";
import { textRenderer, registerRenderer } from "handsontable/renderers";
import { XMLParser } from "fast-xml-parser";
import Color from "color";

// 注册模块
registerAllModules();

// 根据主题和明暗度获取颜色
const getThemeColor = (themeJson, themeId, tint) => {
  let color = "";
  const themeColorScheme = themeJson["a:theme"]["a:themeElements"]["a:clrScheme"];
  switch (themeId) {
    case 0:
      color = themeColorScheme["a:lt1"]["a:sysClr"]["_lastClr"];
      break;
    case 1:
      color = themeColorScheme["a:dk1"]["a:sysClr"]["_lastClr"];
      break;
    case 2:
      color = themeColorScheme["a:lt2"]["a:srgbClr"]["_val"];
      break;
    case 3:
      color = themeColorScheme["a:dk2"]["a:srgbClr"]["_val"];
      break;
    default:
      color = themeColorScheme[`a:accent${themeId - 3}`]["a:srgbClr"]["_val"];
      break;
  }
  // 根据tint修改颜色深浅
  color = "#" + color;
  const colorObj = Color(color);
  if (tint) {
    if (tint > 0) {
      // 淡色
      color = colorObj.lighten(tint).hex();
    } else {
      // 深色
      color = colorObj.darken(Math.abs(tint)).hex();
    }
  }
  return color;
};
// 获取颜色
const getColor = (obj, themeJson) => {
  if ("argb" in obj) {
    // 标准色
    // rgba格式去掉前两位: FFFF0000 -> FF0000
    return "#" + obj.argb.substring(2);
  } else if ("theme" in obj) {
    // 主题颜色
    if ("tint" in obj) {
      return getThemeColor(themeJson, obj.theme, obj.tint);
    } else {
      return getThemeColor(themeJson, obj.theme, null);
    }
  }
};
// 设置边框
const setBorder = (style) => {
  let borderStyle = "solid";
  let borderWidth = "1px";
  switch (style) {
    case "thin":
      borderWidth = "thin";
      break;
    case "dotted":
      borderStyle = "dotted";
      break;
    case "dashDot":
      borderStyle = "dashed";
      break;
    case "hair":
      borderStyle = "solid";
      break;
    case "dashDotDot":
      borderStyle = "dashed";
      break;
    case "slantDashDot":
      borderStyle = "dashed";
      break;
    case "medium":
      borderWidth = "2px";
      break;
    case "mediumDashed":
      borderStyle = "dashed";
      borderWidth = "2px";
      break;
    case "mediumDashDotDot":
      borderStyle = "dashed";
      borderWidth = "2px";
      break;
    case "mdeiumDashDot":
      borderStyle = "dashed";
      borderWidth = "2px";
      break;
    case "double":
      borderStyle = "double";
      break;
    case "thick":
      borderWidth = "3px";
      break;
    default:
      break;
  }
  // console.log(borderStyle, borderWidth);
  return [borderStyle, borderWidth];
};

export default function XLSXPreView() {
  // 表格数据
  const [data, setData] = useState(null);
  // 表格
  const [sheet, setSheet] = useState([]);
  // 主题
  const [themeJson, setThemeJson] = useState([]);
  // 合并的单元格
  const [mergeRanges, setMergeRanges] = useState([]);

  registerRenderer("customStylesRenderer", (hotInstance, td, row, column, prop, value, cellProperties) => {
    textRenderer(hotInstance, td, row, column, prop, value, cellProperties);
    // console.log(cellProperties);
    // 填充样式
    if ("fill" in cellProperties) {
      // 背景颜色
      if ("fgColor" in cellProperties.fill && cellProperties.fill.fgColor) {
        td.style.background = getColor(cellProperties.fill.fgColor, themeJson);
      }
    }
    // 字体样式
    if ("font" in cellProperties) {
      // 加粗
      if ("bold" in cellProperties.font && cellProperties.font.bold) {
        td.style.fontWeight = "700";
      }
      // 字体颜色
      if ("color" in cellProperties.font && cellProperties.font.color) {
        td.style.color = getColor(cellProperties.font.color, themeJson);
      }
      // 字体大小
      if ("size" in cellProperties.font && cellProperties.font.size) {
        // td.style.fontSize = cellProperties.font.size + "px";
      }
      // 字体类型
      if ("name" in cellProperties.font && cellProperties.font.name) {
        td.style.fontFamily = cellProperties.font.name;
      }
      // 字体倾斜
      if ("italic" in cellProperties.font && cellProperties.font.italic) {
        td.style.fontStyle = "italic";
      }
      // 下划线
      if ("underline" in cellProperties.font && cellProperties.font.underline) {
        // 其实还有双下划线，但是双下划綫css中没有提供直接的设置方式，需要使用额外的css设置，所以我也就先懒得弄了
        td.style.textDecoration = "underline";
        // 删除线
        if ("strike" in cellProperties.font && cellProperties.font.strike) {
          td.style.textDecoration = "underline line-through";
        }
      } else {
        // 删除线
        if ("strike" in cellProperties.font && cellProperties.font.strike) {
          td.style.textDecoration = "line-through";
        }
      }
    }
    // 对齐
    if ("alignment" in cellProperties) {
      if ("horizontal" in cellProperties.alignment) {
        // 水平
        // 这里我直接用handsontable内置类做了，设置成类似htLeft的样子。
        //（handsontable）其实至支持htLeft, htCenter, htRight, htJustify四种，但是其是它还有centerContinuous、distributed、fill，遇到这几种就会没有效果，也可以自己设置，但是我还是懒的弄了，用到的时候再说吧
        const name =
          cellProperties.alignment.horizontal.charAt(0).toUpperCase() + cellProperties.alignment.horizontal.slice(1);
        td.classList.add(`ht${name}`);
      }
      if ("vertical" in cellProperties.alignment) {
        // 垂直
        // 这里我直接用handsontable内置类做了，设置成类似htTop的样子。
        const name =
          cellProperties.alignment.vertical.charAt(0).toUpperCase() + cellProperties.alignment.vertical.slice(1);
        td.classList.add(`ht${name}`);
      }
    }
    // 边框
    if ("border" in cellProperties) {
      if ("left" in cellProperties.border && cellProperties.border.left) {
        // 左边框
        const [borderWidth, borderStyle] = setBorder(cellProperties.border.left.style);
        let color = "";
        // console.log(row, column, borderWidth, borderStyle);
        if (cellProperties.border.left.color) {
          color = getColor(cellProperties.border.left.color, themeJson);
        }
        td.style.borderLeft = `${borderStyle} ${borderWidth} ${color}`;
      }
      if ("right" in cellProperties.border && cellProperties.border.right) {
        // 左边框
        const [borderWidth, borderStyle] = setBorder(cellProperties.border.right.style);
        // console.log(row, column, borderWidth, borderStyle);
        let color = "";
        if (cellProperties.border.right.color) {
          color = getColor(cellProperties.border.right.color, themeJson);
        }
        td.style.borderRight = `${borderStyle} ${borderWidth} ${color}`;
      }
      if ("top" in cellProperties.border && cellProperties.border.top) {
        // 左边框
        const [borderWidth, borderStyle] = setBorder(cellProperties.border.top.style);
        let color = "";
        // console.log(row, column, borderWidth, borderStyle);
        if (cellProperties.border.top.color) {
          color = getColor(cellProperties.border.top.color, themeJson);
        }
        td.style.borderTop = `${borderStyle} ${borderWidth} ${color}`;
      }
      if ("bottom" in cellProperties.border && cellProperties.border.bottom) {
        // 左边框
        const [borderWidth, borderStyle] = setBorder(cellProperties.border.bottom.style);
        let color = "";
        // console.log(row, column, borderWidth, borderStyle);
        if (cellProperties.border.bottom.color) {
          color = getColor(cellProperties.border.bottom.color, themeJson);
        }
        td.style.borderBottom = `${borderStyle} ${borderWidth} ${color}`;
      }
    }
  });

  const handleFile = async (e) => {
    const file = e.target.files[0];

    const workbook = new Excel.Workbook();
    await workbook.xlsx.load(file);

    const worksheet = workbook.getWorksheet(1);

    // const sheetRows = worksheet.getRows(1, worksheet.rowCount);
    setSheet(worksheet);

    // console.log(worksheet.getCell(1, 1).style);

    // 遍历工作表中的所有行（包括空行）
    const sheetData = [];
    worksheet.eachRow({ includeEmpty: true }, function (row, rowNumber) {
      // console.log('Row ' + rowNumber + ' = ' + JSON.stringify(row.values));
      // 使用row.values获取每一行的值时总会多出一条空数据(第一条)，这里我把它删除
      const row_values = row.values.slice(1);
      sheetData.push(row_values);
    });
    setData(sheetData);

    // 将主题xml转换成json
    const themeXml = workbook._themes.theme1;
    const options = {
      ignoreAttributes: false,
      attributeNamePrefix: "_",
    };
    const parser = new XMLParser(options);
    const json = parser.parse(themeXml);
    setThemeJson(json);

    // 获取合并的单元格
    const mergeCells = [];

    for (let i in worksheet._merges) {
      const { top, left, bottom, right } = worksheet._merges[i].model;
      mergeCells.push({ row: top - 1, col: left - 1, rowspan: bottom - top + 1, colspan: right - left + 1 });
    }
    setMergeRanges(mergeCells);
    console.log(worksheet);
  };

  return (
    <>
      <div>
        <input type="file" id="_xx_file" onChange={handleFile} accept=".xls,.xlsx" />
      </div>
      <div id="table_view">
        {!!data && (
          <HotTable
            data={data}
            readOnly={true}
            rowHeaders={true}
            colHeaders={true}
            width="100vw"
            height="auto"
            licenseKey="non-commercial-and-evaluation"
            rowHeights={function (index) {
              if (sheet.getRow(index + 1).height) {
                // exceljs获取的行高不是像素值，事实上，它是23px - 13.8 的一个映射。所以需要将它转化为像素值
                return sheet.getRow(index + 1).height * (23 / 13.8);
              }
              return 23; // 默认
            }}
            colWidths={function (index) {
              if (sheet.getColumn(index + 1).width) {
                // exceljs获取的列宽不是像素值，事实上，它是81px - 8.22 的一个映射。所以需要将它转化为像素值
                return sheet.getColumn(index + 1).width * (81 / 8.22);
              }
              return 81; // 默认
            }}
            cells={(row, col, prop) => {
              const cellProperties = {};
              const cellStyle = sheet.getCell(row + 1, col + 1).style;

              if (JSON.stringify(cellStyle) !== "{}") {
                // console.log(row+1, col+1, cellStyle);
                for (let key in cellStyle) {
                  cellProperties[key] = cellStyle[key];
                }
              }
              return { ...cellProperties, renderer: "customStylesRenderer" };
            }}
            mergeCells={mergeRanges}
          />
        )}
      </div>
    </>
  );
}
